#pragma once

#include<iostream>
#include<pthread.h>
#include<queue>


namespace wyl
{
    const int default_num = 5;
    template<class T>
    class thread_pool
    {
    private:
        int _num; //队列最大长度
        std::queue<T> _sq; //任务队列
        pthread_mutex_t _mutex; //锁
        pthread_cond_t _cond; //条件变量

    public:
        thread_pool(int num = default_num)
        :_num(num)
        {
            pthread_mutex_init(&_mutex,nullptr);
            pthread_cond_init(&_cond,nullptr);
        }
        ~thread_pool()
        {
            pthread_mutex_destroy(&_mutex);
            pthread_cond_destroy(&_cond);
        }

    private:
        void Lock()
        {
            pthread_mutex_lock(&_mutex);
        }
        void UnLock()
        {
            pthread_mutex_unlock(&_mutex);
        }
        bool Isfull()
        {
            return _num == _sq.size();
        }
        bool Isempty()
        {
            return _sq.size() == 0;
        }
        //等待
        void Wait()
        {
            pthread_cond_wait(&_cond,&_mutex);
        }
        //唤醒
        void Wakeup()
        {
            pthread_cond_signal(&_cond);
        }
       
    public:
        static void* Rountine(void* args)
        {
            pthread_detach(pthread_self());//分离线程
            thread_pool<T>* tp = (thread_pool<T>*)args;
            //处理任务
            while(true)
            {
                tp->Lock();
                while(tp->Isempty())
                {
                    //任务队列为空，等待
                    tp->Wait();
                }
                //从队列里取出任务
                T t;
                tp->Pop(&t);
                tp-> UnLock();
                t(); //执行任务

            }
            
        } 
        //初始化线程池
        void pool_init()
        {
            pthread_t tid;
            for(int i = 0; i<_num;i++)
            {
                pthread_create(&tid,nullptr,Rountine,(void*)this);
            }
        }
        void Push(const T& in)
        {
            Lock();
            //把任务放进任务队列
            _sq.push(in);
            UnLock();
            Wakeup();
        }
        void Pop(T* out)
        {  
            *out = _sq.front(); 
            _sq.pop();
        }
    } ;
}
